A type of HTML frame which contains content from another document or site. Think of it as a mini-browser with no controls. For more info see [[IFRAME - Inline Frame|http://www.htmlhelp.com/reference/html40/special/iframe.html]].
!!Embedding the <iframe> in a tiddler\nEmbedding the iframe without it showing itself involves several things. Here is an example of what I ended up with. Refer to the examples of embedding in [[Embedding the <iframe>]].\n* If the iframe is refreshed in place, a bug in IE6 causes it to initially be drawn way too wide, extending off the right side of the browser. Moving the mouse over the tiddler causes it to be redrawn correctly. The cure for this was to enclose the iframe in an invisible table. The table need not have any cells. then, @@and this is important@@, control the width of the iframe via the enclosing table's width, setting the iframe's width to 100%.\n* But in FireFox, the enclosing table causes a small strip of the table's background color to show at the bottom, below the iframe. Since I wanted everything to inherit the tiddler's styles, this was unacceptable. Adding the style {{{background:transparent}}} to the table cured that one.\n* Because of box-model differences, I put a 1 pixel margin around the enclosing table. Without it, in FireFox the table could obscure elements just above or below it.\n* In IE6, a small strip of gray appears below the iframe, within the enclosing table, unless you include {{{allowtransparency}}} in the iframe attributes.\n* In FireFox, using a width of 100% on the enclosing table causes it to be too wide. It's OK in IE6. As you start to reduce the table width percentage, in FireFox, all of a sudden it starts acting right. I discovered that 96% is a good compromise between the two browsers.
Introduction
Embedding the iframe into the tiddler without it showing itself involves several things. Here are a couple of examples of what I ended up with. See [[Browser-Specific Quirks]] for the reasons behind most of this. Notes here refer to general issues.\n!!!Borders around iframes\nIn order to allow theme switching, I put CSS into the applicable stylesheet to control the iframe's border color, etc. This border can be supressed with a style override in a specific iframe tag. Note that I never used the enclosing table's border. I tried it, and box model differences between browsers drive me buggy. And the border is really enclosing the iframe anyway, right?\n{{{\n.viewer iframe { border: 1px solid blue; }\n}}}\n!!!Avoiding tags and tagging blocks\n//(thanks to [[Daniel Baird|http://danielbaird.com/]] for this one)// The tags and tagging blocks that appear in tiddlers are floating elements. In order to keep the iframe from covering them, the enclosing table must contain CSS {{{clear:both;}}}. This causes the iframe to be drawn below those areas, possibly leaving blank space above it in the tiddler (if there's not enough normal tiddler content above the iframe to push it down far enough in the first place).\n!!!Fixed-height <iframe> with CSS border\nThis embeds a fixed height iframe with the border specified in the TiddlyWiki CSS in effect. \n{{{\n<html>\n <table width="96%" style="border:none;margin:1px;background:transparent;clear:both;">\n <iframe src="xyzzy.asp" width="100%" height="302px" \n scrolling="no" frameborder="0" allowtransparency>\n </iframe>\n </table>\n</html>\n}}}\n\n!!![[Self-Sizing <iframe>]]\nThis iframe has the CSS border supressed with a style override, as it is designed to appear invisibly within a tiddler, self-sizing itself vertically as contant within the iframe changes. \n{{{\n<html>\n <table width="96%" style="border:none;margin:1px;background:transparent;clear:both;">\n <iframe id="xyzzy" src="xyzzy.asp" width="100%" height="0" \n scrolling="no" frameborder="0" allowtransparency style="border: 0px;">\n </iframe>\n </table>\n</html>\n}}}\nNote the {{{height="0"}}} and the {{{id="xyzzy"}}} which (by my convention) is the same as the file-name portion of the URI of the frame source. See [[Self-Sizing <iframe>]].
Mozilla FireFox browser, V1.5 or later.
<div class='header' macro='gradient vert #390108 #900'>\n<div class='headerShadow'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;\n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n<div class='headerForeground'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;\n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n</div>\n<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>\n<div id='sidebar'>\n<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>\n</div>\n<div id='displayArea'>\n<div id='messageArea'></div>\n<div id='tiddlerDisplay'></div>\n</div>
/***\nAuthor: //unknown// - originally retrieved from Clint Checketts (http://www.checkettsweb.com) \n!!Revision History\n<<<\n''2006.09.17 [rbd]'' Get rid of ghost blue borders on <input> and <textarea> elements within both the editor and the viewer content. Mute the background of <input> and <textarea> to reduce the glare of them against the dark background. Change highlighting color to match the style. Fix table cell borders so they show. Fix buttons so they don't display dotted underline hyperlink when clicked or hovered, brighten the normal text within buttons, perceptually it was too dark! Reformat rules to multi-line with tabs.\n''2006.09.18 [rbd]'' Add overrides for ~XP-style navbar used on Share Your Sky! main page.\n''2006.09.19 [rbd]'' More work on styles, improved bar graphics, tweaks for boxing, non-hyperlinked fonts. Looking good now.\n''2006.09.20 [rbd]'' Add background and border to tiddlers, adjust padding and bottom margin for same. Remove rbd marks and dead styles. Reduce header and sidebar borders to 1px. Added Clint Checketts' IE CSS hack to permit the .tiddler CSS to work correctly. How'd he EVER figure that out?\n''2006.09.30 [rbd]'' Fix "dotted-line removal" change above so buttons in viewer don't change size when highlighted. This made flickering buttons!\n<<<\n!Generic Layout Rules \n***/\n/*{{{*/\nbody {\n background: #000;\n position: static; /*Clint's IE fix part 1 */\n}\n\n.tagClear{\n margin-top: 1em;\n clear: both; /* Clint's IE fix part 2 */\n}\n\ntextarea {\n /* Fixed point font for editing */\n font-family: courier !important;\n}\n\n/*}}}*/\n/***\n!Link styles\n***/\n/*{{{*/\na,\na.button,\n#mainMenu a.button,\n#sidebarOptions .sliderPanel a {\n color: #ffbf00;\n border: 0;\n}\n\na:hover,\na.button:hover,\n#mainMenu a.button:hover,\n#sidebarOptions .sliderPanel a:hover\n#sidebarOptions .sliderPanel a:active {\n color: #ff7f00;\n border: 0;\n border-bottom: #ff7f00 1px dashed;\n background: transparent;\n text-decoration: none;\n}\n\n#displayArea .button.highlight {\n color: #ffbf00;\n background: #4c4c4c;\n}\n\n/*}}}*/\n/***\n!Header styles\n***/\n/*{{{*/\n.header{\n border-bottom: 1px solid #ffbf00;\n color: #fff;\n}\n\n.headerForeground a {\n color: #fff;\n}\n\n.header a:hover {\n border-bottom: 1px dashed #fff;\n}\n\n/*}}}*/\n/***\n!Main menu styles\n***/\n/*{{{*/\n#mainMenu {\n color: #fff;\n}\n\n#mainMenu h1{\n font-size: 1.1em;\n}\n\n#mainMenu li,#mainMenu ul{\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n/*}}}*/\n/***\n!Sidebar styles \n***/\n/*{{{*/\n#sidebar {\n right: 0;\n color: #fff;\n border: 1px solid #ffbf00;\n border-width: 0 0 1px 1px;\n}\n\n#sidebarOptions {\n background-color: #4c4c4c;\n padding: 0;\n}\n\n#sidebarOptions a{\n margin: 0;\n color: #ffbf00;\n border: 0;\n}\n\n#sidebarOptions a:hover {\n color: #4c4c4c;\n background-color: #ffbf00;\n}\n\n#sidebarOptions a:active {\n color: #ffbf00;\n background-color: transparent;\n}\n\n#sidebarOptions .sliderPanel {\n background-color: #333;\n margin: 0;\n}\n\n#sidebarOptions input {\n border: 1px solid #ffbf00;\n background-color: #ffffcc;\n}\n\n#sidebarTabs {\n background-color: #4c4c4c;\n}\n\n#sidebarTabs .tabSelected {\n padding: 3px 3px;\n cursor: default;\n color: #ffbf00;\n background-color: #666;\n}\n\n#sidebarTabs .tabUnselected {\n color: #ffbf00;\n background-color: #5f5f5f;\n padding: 0 4px;\n}\n\n#sidebarTabs .tabUnselected:hover,\n#sidebarTabs .tabContents {\n background-color: #666;\n}\n\n.listTitle{\n color: #FFF;\n}\n\n#sidebarTabs .tabContents a{\n color: #ffbf00;\n}\n\n#sidebarTabs .tabContents a:hover{\n color: #ff7f00;\n background: transparent;\n}\n\n#sidebarTabs .txtMoreTab .tabSelected,\n#sidebarTabs .txtMoreTab .tab:hover,\n#sidebarTabs .txtMoreTab .tabContents{\n color: #ffbf00;\n background: #4c4c4c;\n}\n\n#sidebarTabs .txtMoreTab .tabUnselected {\n color: #ffbf00;\n background: #5f5f5f;\n}\n\n.tab.tabSelected, .tab.tabSelected:hover{\n color: #ffbf00;\n border: 0;\n background-color: #4c4c4c;\n cursor: default;\n}\n\n.tab.tabUnselected {\n background-color: #666;\n}\n\n.tab.tabUnselected:hover{\n color: #ffbf00;\n border: 0;\n background-color: #4c4c4c;\n}\n\n.tabContents {\n background-color: #4c4c4c;\n border: 0;\n}\n\n.tabContents .tabContents{\n background: #666;\n}\n\n.tabContents .tabSelected{\n background: #666;\n}\n\n.tabContents .tabUnselected{\n background: #5f5f5f;\n}\n\n.tabContents .tab:hover{\n background: #666;\n}\n\n/*}}}*/\n/***\n!Message area styles\n***/\n/*{{{*/\n#messageArea {\n background-color: #666;\n color: #fff;\n border: 2px solid #ffbf00;\n}\n\n#messageArea a:link, #messageArea a:visited {\n color: #ffbf00;\n text-decoration: none;\n}\n\n#messageArea a:hover {\n color: #ff7f00;\n}\n\n#messageArea a:active {\n color: #ff7f00;\n}\n\n#messageArea .messageToolbar a{\n border: 1px solid #ffbf00;\n background: #4c4c4c;\n}\n\n/*}}}*/\n/***\n!Popup styles \n***/\n/*{{{*/\n#popup {\n color: #fff;\n background-color: #4c4c4c;\n border: 1px solid #ffbf00;\n}\n\n#popup a {\n color: #ffbf00;\n}\n\n#popup a:hover {\n background: transparent;\n color: #ff7f00;\n border: 0;\n}\n\n#popup hr {\n color: #ffbf00;\n background: #ffbf00;\n}\n\n/*}}}*/\n/***\n!Tiddler Display styles\n***/\n/*{{{*/\n/** LOSER ON IE6 without Clint's IE fix (see body section at top!) **/\n.tiddler {\n background: #000030;\n border: 1px solid #000080;\n padding-bottom: 8px;\n margin-left: 8px; /* Vastly different on IE vs FireFox! */\n margin-bottom: 12px;\n}\n\n.tiddler .button {\n color: #808080;\n}\n\n.tiddler .button:hover,\n.tiddler .button:active {\n color: #ffbf00;\n background-color: #4c4c4c;\n border-bottom: 1px solid #4c4c4c; /* No dotted line in buttons */\n}\n\n.title{\n color: #fffacd;\n border-bottom: 1px dashed #333;\n}\n\nh1, h2, h3, h4, h5 {\n color: #fffacd;\n background-color: #000040;\n border-top: 1px solid #333;\n border-bottom: 1px solid #333;\n}\n\n.subtitle{\n color: #666;\n}\n\n.viewer {\n color: #fff;\n}\n\n.viewer table{\n background: #666;\n color: #fff;\n}\n\n.viewer th {\n background-color: #996;\n color: #fff;\n}\n\n.viewer td, .viewer tr {\n border: 1px solid #333;\n}\n\n.viewer pre, .viewer code {\n color: #ddd;\n background-color: #4c4c4c;\n border: 1px solid #ffbf00;\n}\n\n.viewer hr {\n color: #666;\n}\n\n.viewer iframe {\n border: 1px solid #ffbf00;\n}\n\n.viewer .button:hover,\n.viewer .button:active {\n border: 1px solid #4c4c4c; /* Needed to avoid button size changing */\n}\n\n.editor textarea, .editor input {\n border: 1px solid #ffbf00;\n background-color: #ffffcc;\n}\n\n.toolbar {\n color: #4c4c4c;\n}\n\n.toolbar a.button,\n.editorFooter a{\n border: 0;\n}\n\n.footer {\n color: #ddd;\n}\n\n.selectedTiddler .footer {\n color: #888;\n}\n\n.highlight, .marked {\n color: #000;\n background-color: #ffe72f;\n}\n\n.editorFooter {\n color: #aaa;\n}\n\n.tab{\n -moz-border-radius-topleft: 3px;\n -moz-border-radius-topright: 3px;\n}\n\n.tagging,\n.tagged{\n background: #4c4c4c;\n border: 1px solid #4c4c4c;\n}\n\n.selected .tagging,\n.selected .tagged{\n background: #000;\n border: 1px solid #ffbf00;\n}\n\n.tagging .listTitle,\n.tagged .listTitle{\n color: #fff;\n}\n\n.tagging .button,\n.tagged .button{\n color: #ffbf00;\n border: 0;\n padding: 0;\n}\n\n.tagging .button:hover,\n.tagged .button:hover{\n background: transparent;\n}\n\n.highlight, .marked {\n background-color: #000080;\n color: #ffffff;\n}\n\n.cascade {\n background: #4c4c4c;\n color: #ddd;\n border: 1px solid #ffbf00;\n}\n\n/*}}}*/\n/***\n!XP ~NavBar Style Overrides\n***/\n/*{{{*/\n.topItem {\n background: url("im/fire-classic-up.png") no-repeat 0 0;\n color: #ffbf00;\n}\n\n.topItemOver {\n background: url("im/fire-classic-up-on.png") no-repeat 0 0;\n color: #ffffff;\n}\n\n.topItemClose {\n background: url("im/fire-classic-down.png") no-repeat 0 0;\n color: #ffbf00;\n}\n\n.topItemCloseOver {\n background: url("im/fire-classic-down-on.png") no-repeat 0 0;\n color: #ffffff;\n}\n\n.dropMenu {\n background-color: #4c4c4c;\n color: #000;\n border: 1px solid;\n border-color: #4c4c4c #ff7f00 #ff7f00 #ff7f00;\n}\n\n.subItem, .subSubItem {\n color: #ffffff;\n}\n\n.subItemOver, .subSubItemOver {\n color: #ffffff;\n}\n\n/*}}}*/\n
Microsoft Internet Explorer V6
In order to support the styling of the ~TiddlyWiki (including theme switching) within the iframe, making it appear seamlessly, I needed to have the iframe inherit the styles in effect in the ~TiddlyWiki. This turned out to be pretty tricky. Most of the logic is contained in the [[iframecss.js]] Javascript file, which is loaded into the iframe's source HTML. \n\nI wanted to make the tiddler independent of this, so I chose the model where the iframe's HTML is responsible for accessing and loading the enclosing tiddler's styles into its own CSS. See [[Template <iframe> Source]].\n\nThe first thing to note is call to load the inheritance support code [[iframecss.js]]:\n{{{\n<script src="iframecss.js"></script>\n}}}\nThis must come first, and be in the {{{<head>}}} section of the iframe source HTML. The result of executing the code in this script (see below) is to have the __entire set__ of the host ~TiddlyWiki's ~CSS inserted immediately after the call to the script. Thus, any explicit CSS following that will override the inherited TW's CSS. After this, the iframe has all of the same CSS rules as the host ~TiddlyWiki!\n\nThe next section is CSS that overrides the border, margin, and padding of the .tiddler and .viewer classes in ~TiddlyWiki CSS:\n{{{\n<style>\n .tiddler { border: none; margin: 0; padding: 0; }\n .viewer { border: none; margin: 0; padding: 0; }\n</style>\n}}}\nThis allows the content in the iframe to be seamlessly embedded into the enclosing tiddler without the TW's CSS imposing additional borders, margins, or padding. Basically, if the iframe's content has no border. margin, or padding, it will butt right up against the edges of the iframe.\n\nThe next section opens nested {{{<div>}}} elements which must enclose ///all/// of the content in the iframe. These effectively place the iframe content into tiddler/viewer context just like the content in the tiddlers themselves.\n{{{\n<div class="tiddler" id="tdiv"><div class="viewer" id="vdiv">\n}}}\nWe'll need to get a handle to the tiddler-class div later, so we give it an id. Remember that the scope of this is within the iframe, and is invisible to the ~TiddlyWiki.\n\nNext is the actual content for the iframe. Anything goes here; again, this is a separate HTML document, and executes within the iframe, invisible to the ~TiddlyWiki. \n{{{\n... iframe content goes here...\n}}}\nFollowing this, we close the tiddler/viewer {{{<div>}}} elements. We must do this here because they must exist for the next tasks to work!\n{{{\n</div></div>\n}}}\nSince the iframe content is running in a world of its own, we need to do some magic in order to get the CSS styles in effect for the parent tiddler. the following Javascript block must appear at the end of the iframe content (well, before the {{{</body></html>}}} but you get what I mean). It must be able to access at least the tiddler {{{<div>}}}.\n{{{\n<script language="Javascript" type="text/javascript">\n document.body.style.backgroundColor = \n getStyle(document.getElementById("tdiv"), 'background-color');\n</script>\n}}}\nThis is magic; refer to [[iframecss.js]]. Here's the issue that gives rise to the need for this code: We've already inherited the ~TiddlyWiki's CSS and placed the iframe's content within tiddler/viewer class contexts, so it's just like the content is in the viewer area of a tiddler (well, except we zapped the border, margin, and padding of the tiddler and viewer). But if the content doesn't fill the iframe area, the remainder of the area will be filled with the background color of the ~TiddlyWiki body. Remember? We inherited //all// of the styles of the ~TiddlyWiki.\n\nIn order for the iframe to appear seamlessly within a tiddler, the empty area within the iframe needs to have the background color of the //tiddler//, not the background color of the whole ~TiddlyWiki! So we set the {{{<body>}}} background-color of the iframe content to the background-color of the tiddler class. Note that I don't use the background of the //viewer// though it woould be simple to do that (just change "tdiv" to "vdiv" above!). The {{{getStyle()}}} function is cross-browser (well, IE6 and FireFox anyway). We have [[Robert Nyman|http://www.robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/]] to thank for this bit of magic. Personally I got a big charge out of it once I figured it out.\n\nNow have a look at [[Self-Sizing <iframe>]], where we make the iframe adjust itself to the vertical size of its content, giving the iframe an even more seamless embedded appearance.
@@Read this document first in the order of the Main Menu@@\n\nAs part of the new content development for my [[Share Your Sky!|http://ShareyourSky.com/]] astronomical observatory control and remote observing system, I did quite a bit of work (and learned a lot) with regard to using [[<iframe>]] elements within tiddlers. This document was written to serve as a tickler for me, and for others to benefit from my work and knowledge gained. My goals:\n* Allow iframes to appear within tiddlers seamlessly:\n** Determine how to supress the iframe's borders, margins, etc.\n** Inherit the tiddler's styles, so that style-switching will carry into the iframe's content.\n** Allow the iframe to adjust its height automatically based on the size of its content.\n* Provide a refresh control, including automatic periodic refreshing. This arose from the fact that most of the iframes in Share Your Sky! are used to display dynamic/changing data coming from a server. \n* Handle any [[Browser-Specific Quirks]] that are encountered in the above.\n\n//Robert B. Denny//\n//rdenny@dc3.com//\n//September, 2006//\n\n
[[Introduction|Introduction]]\n[[Embedding|Embedding the <iframe>]]\n[[Inheriting Styles|Inheriting the Tiddler Styles]]\n[[Self-Sizing|Self-Sizing <iframe>]]\n[[Refreshing|Refreshing the <iframe>]]\n[[Sample|Sample Self-Sizing <iframe>]]\n[[Security|Security Issues]]\n
/***\n|''Name:''|RefreshTiddlerPlugin|\n|''Description:''|Refresh an entire tiddler with optional periodic re-refresh|\n|''Date:''|Oct 3, 2006|\n|''Source:''|http://solo.dc3.com/tw/index.html#RefreshTiddlerPlugin|\n|''Author:''|Bob Denny ~DC-3 Dreams, SP|\n|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|\n|''Version:''|1.0.4|\n|''~CoreVersion:''|2.0.11, 2.1.0|\n|''Browser:''|Firefox 1.5; Internet Explorer 6.0; Safari|\n|''Require:''|CheckboxPlugin (http://www.TiddlyTools.com/#CheckboxPlugin)|\nThis macro provides a tiddler with refresh control. At a minimum, a refresh button appears at the location of the macro invocation. Clicking this button causes the contents of the tiddler to be refreshed. Optionally, a checkbox may also be displayed with which the user can enable and disable automatic periodic refresh of the tiddler at a specified interval.\nThere are three optional parameters\n|!Parameter|!Description|\n|''1''|Button label, default "Refresh"|\n|''2''|Button tooltip, default "Refresh this tiddler"|\n|''3''|Periodic refresh interval, sec., default 0 (no periodic refresh checkbox)|\n!!Revision History\n<<<\n''2006.09.13 [1.0.1]'' Initial creation, several days\n''2006.09.22 [1.0.2]'' Make periodic refresh checkbox optional\n''2006.09.29 [1.0.3]'' Refresh checkbox cookie names different from RefreshIframe.\n''2006.10.03 [1.0.4]'' Lint check, validate on TW 2.1.0.\n<<<\n!!Code\n***/\n//{{{\nversion.extensions.RefreshTiddler = {\n major: 1, minor: 0, revision: 4,\n date: new Date(2006, 10, 3), \n type: 'macro',\n source: "#RefreshTiddlerPlugin"\n};\n\nconfig.macros.RefreshTiddler = \n{\n states: { }, // Associative array of refresh states indexed by tiddler name\n \n handler: function(place, macroName, params, wikifier, paramString, tiddler)\n {\n var tidTitle = tiddler.title; // Shortcut\n if(!this.states[tidTitle]) this.states[tidTitle] = { // Array of state objects for refreshed tiddlers\n butLabel: "",\n butTooltip: "",\n refInterval: 0,\n doRefresh: false,\n initPerRef: false,\n timerId: 0,\n chkBox: null\n };\n var state = this.states[tidTitle]; // Shortcut\n state.butLabel = params[0] ? params[0] : "Refresh"; // Make these react to edits\n state.butTooltip = params[1] ? params[1] : "Refresh this tiddler";\n state.refInterval = params[2] ? params[2] : 0; // 0 = no periodic refresh checkbox\n var btn = createTiddlyButton(place, state.butLabel, state.butTooltip, this.onButClick);\n btn.name = tidTitle; // Set button name to tiddler name (see onButClick())\n if(state.refInterval > 0) // If periodic refresh wanted\n {\n wikify(" [ =chkPerRefTid" + tiddler.created.convertToYYYYMMDDHHMM() + // Uniquify chkbox ID\n "{config.macros.RefreshTiddler.states[\s"" + tidTitle + "\s"].chkBox = this;}" +\n "{config.macros.RefreshTiddler.onChkClick(\s"" + tidTitle + "\s");}] " + \n state.butLabel + " every " + state.refInterval + " seconds", place);\n state.timerId = 0;\n if(!state.initPerRef) this.onChkClick(tidTitle); // Simulate checkbox click (state already from cookie)\n }\n },\n \n onButClick: function(e) \n {\n if(!e) e = window.event;\n var tidTitle = resolveTarget(e).name; // Name is the tiddler name!\n //displayMessage("but " + tidTitle);\n story.refreshTiddler(tidTitle, null, true);\n return false;\n },\n \n onChkClick: function(tidTitle) \n {\n var state = this.states[tidTitle];\n if(state.chkBox.checked) {\n if(state.timerId) clearTimeout(state.timerId);\n this.startRefresh(tidTitle); \n } else { \n state.doRefresh = false;\n }\n state.initPerRef = true;\n },\n \n startRefresh: function(tidTitle) \n {\n var state = this.states[tidTitle];\n state.doRefresh = true;\n //displayMessage("st " + tidTitle + " " + state.refInterval);\n state.timerId = setTimeout("config.macros.RefreshTiddler.reRefresh(\s"" + \n tidTitle + "\s")", state.refInterval * 1000);\n },\n \n reRefresh: function(tidTitle)\n {\n var state = this.states[tidTitle];\n state.timerId = 0;\n if(!state.doRefresh) return;\n // Kill re-refresh cycle if tiddler closed or edited\n var tidElem = document.getElementById(story.idPrefix + tidTitle); // DON'T GET CUTE! THIS IS CORRECT!\n //**BUGBUG** Hardwired to EditTemplate!\n if(!tidElem || tidElem.attributes['template'].value == "EditTemplate") // Prevent hidden or editing\n {\n state.initPerRef = false;\n return;\n }\n //displayMessage("re " + tidTitle + " " + state.refInterval);\n story.refreshTiddler(tidTitle, null, true);\n state.timerId = setTimeout("config.macros.RefreshTiddler.reRefresh(\s"" + \n tidTitle + "\s")", state.refInterval * 1000);\n }\n};\n//}}}\n
>If you haven't yet looked at [[Inheriting the Tiddler Styles]] then [[Self-Sizing <iframe>]], do so now, as this builds on the techniques described there.\nSo far, we have a way to suck external content (that we have produced!) into a tiddler. By itself this isn't too interesting, as we could just put the content right into the tiddler in the first place. Where this comes into its own is if the external content is //dynamic//, for example the output of a PHP or ASP page, or a CGI script. In this case, when the tiddler is opened, the iframe is (re)loaded and you can see the changing content. \n\nBut it can be annoying to have to close and reopen the tiddler just to update the dynamic content in the iframe. This led me to build the RefreshTiddlerPlugin. You can read all about it in the doc that is embedded within the plugin. To use it, add a macro call to ~RefreshTiddler immediately after the {{{</table>}}} of the table that encloses the {{{<iframe>}}} in the tiddler. After you do, you'll have one or more ways to relod the iframe without closing and reopening the tiddler.
This is the ifsample1 ASP page that generates the variable gibberish for the embedded iframe. Thisi could be anything as long as it follows the rules described herein for [[Embedding the <iframe]].\n{{{\n<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" \n "http://www.w3.org/TR/REC-html40/loose.dtd"> \n<%@ LANGUAGE="JSCRIPT" %><html>\n<head>\n<script src="iframecss.jsc" language="Javascript" type="text/javascript"></script>\n<!-- parent's stylesheets get inserted here -->\n<style>\n .tiddler { border: none; margin: 0; padding: 0; }\n .viewer { border: none; margin: 0; padding: 0; }\n</style>\n</head>\n<body>\n<div class="tiddler" id="tdiv"><div class="viewer" id="vdiv">\nHere is some content that will change in length each time the page is fetched:\n<%\nvar lorem = "<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse vitae lectus. " + \n "Donec dictum, nisi eget ullamcorper accumsan, nisl mauris imperdiet metus, sed dictum metus turpis " +\n "sed velit. Donec id ligula blandit orci ullamcorper nonummy. Praesent nulla. Nulla tempor semper " + \n "dui. Curabitur nec dolor. Praesent bibendum pede nec purus. Suspendisse eget nisl vel nulla " +\n "lobortis pellentesque. Proin blandit, orci in interdum laoreet, magna nulla ullamcorper orci, ac " +\n "mattis augue tortor sed ante. Nunc vel turpis. Aliquam erat volutpat. Vestibulum elementum rutrum " +\n "ligula. Nam posuere pharetra dui.</p>\sn" + \n"<p>Nam aliquet. In volutpat, purus a tempor eleifend, nulla nulla tincidunt tortor, laoreet aliquet " +\n "ligula augue vehicula felis. Curabitur sit amet libero at dolor pellentesque faucibus. Vestibulum " +\n "ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed mattis. Sed " +\n "accumsan ipsum at metus. Phasellus urna. Curabitur vel nibh. Donec in arcu aliquet nisi luctus " +\n "luctus. Donec porta. Praesent sollicitudin tempus tortor. Vestibulum euismod facilisis augue. Donec " +\n "aliquam sodales ante. Sed sem pede, mattis non, convallis quis, ullamcorper eu, tortor.</p>";\nResponse.Write(lorem.substr(0, 1 + (Math.random() * lorem.length)));\n%>\n</div></div>\n<script language="Javascript" type="text/javascript">\n var tdiv = document.getElementById('tdiv');\n document.body.style.backgroundColor = getStyle(tdiv, 'background-color');\n parent.document.getElementById("ifsample1").height = tdiv.offsetHeight + 16;\n</script>\n</body>\n</html>\n}}}
Below is dynamically inserted info, via an iframe. Try changing the theme from default to Fire and see the styles in the iframe change right along with the ~TiddlyWiki! Here is the [[Sample Remote Page]].\n----\n<html><table width="96%" style="border:none;margin:1px;background:transparent;clear:both;"><iframe id="ifsample1" src="http://solo.dc3.com/tw/ifsample1.asp" width="100%" height="0" scrolling="no" frameborder="0" allowtransparency style="border:none;"></iframe></table></html><<RefreshTiddler>>
There are security issues with using iframes whose content loads scripts with {{{<script src=...>}}}. Basically, if the ~TiddlyWiki document, the [[iframecss.js]] script, and the active pages for the iframes all reside in the same place, you're good. Mixing web and local places willl lead to problems ("permission denied"). I don't have the time to go into all of this here.
/***\n\n''This plugin was previously called StyleChooser.''\n\n|Name|SelectThemePlugin|\n|Created by|SimonBaird and SaqImtiaz|\n|Location|http://lewcid.googlepages.com/lewcid.html#SelectThemePlugin|\n|Version|1.2.4|\n|Requires|~TW2.x|\n!Description\n*An alternative style switcher, can be used to switch just stylesheets and/or pagetemplates, or a combination of both (a theme)\n*you can add your own stylesheets and pagetemplates, or use a ThemePack, like BigThemePack.\n\n!Usage\n* You have to have fetch or create some styleSheets and pageTemplates to use this plugin.\n**You can either get a ThemePack like BigThemePack which automatically adds themes to ThemeSelect.\n**or create tiddlers with styleSheets and pageTemplates and tag them styleSheets and pageTemplates respectively.\n* Put {{{<<themeSelect style 'Select theme'>>}}} in your SideBarOptions.\n\n!Creating Theme Packs\n*You can create your own theme pack if you like. Instructions can be found [[here.|CreateThemePack]]\n\n!History\n* 08-Sept-06, v1.2.4, fixed bug with TW2.1\n* 15-May-06, v1.2.3, added paramifier so you can put theme on url, eg http://www.somewhere.com/twfile.html#theme:Berry2, thanks Clint (Simon).\n* 28-Apr-o6, v1.2.2, fixed bug with opening TW after deleting themepacks. (Saq)\n* 26-Apr-06, v1.2.1, more code optimization, dropdowns now updated on the fly. (Saq)\n* 25-Apr-06, v1.2.0, added 3rd party ThemePack support, and made various other improvements.(Simon & Saq)\n* 24-Apr-06, v1.1.0, added: no styles and default styles options,<<br>>support for ThemePack, support for tag variations(Saq)\n* 21-Apr-06, v1.0.0, Reworked dropdowns to include option for pagetemplates (Saq)\n* 21-Apr-06, v0.9.0, Rewrote and added Saq's lovely dropdown select (Simon)\n* 20-Apr-06, v0.0.1, Basic switcher working (Simon)\n\n!Examples\n|!Source|!Output|h\n|{{{<<themeSelect style>>}}} for a dropdown with StyleSheets|<<themeSelect style>>|\n|{{{<<themeSelect pagetemplate>>}}} for a dropdown with PageTemplates|<<themeSelect pagetemplate>>|\n|{{{<<themeSelect style customlabel>>}}} to use a customlabel|<<themeSelect style customlabel>>|\n* When applying a stylesheet or template, it also looks for a template or stylesheet respectively based on naming convention, eg MyFunkyStyleSheet and MyFunkyPageTemplate.\n\n!Notes\n* See also http://www.tiddlytools.com/#SelectStyleSheetPlugin for a more feature-rich style sheet switcher\n\n! Ideas\n* do ViewTemplate also?\n* Pretty up the [x] bit\n\n!Code\n***/\n//{{{\n// for compatibility with TW <2.0.9\nif (!Array.prototype.contains)\n Array.prototype.contains = function(item)\n {\n return this.find(item) != null;\n };\n\n// for compatibility with TW <2.0.9\nif (!Array.prototype.containsAny)\n Array.prototype.containsAny = function(items)\n {\n for(var i=0; i<items.length; i++)\n if (this.contains(items[i]))\n return true;\n return false;\n };\n//}}}\n\n//{{{\nversion.extensions.SelectThemePlugin = { \n major: 1, minor: 2, revision: 4, \n date: new Date(2006,9,8),\n type: 'macro',\n source: "http://lewcid.googlepages.com/lewcid.html#SelectTheme"\n};\n\nconfig.SelectTheme = {\n things: {\n style: {\n tag: ["StyleSheets","StyleSheet","styleSheet","styleSheets","stylesheet","stylesheets"],\n theDefault: "StyleSheet",\n suffix: "StyleSheet",\n notify: refreshStyles,\n cookie: "txtStyleSheet",\n otherThing: "pagetemplate",\n label: "Choose StyleSheet: ",\n tooltip: "Choose a StyleSheet",\n caseNone: { text:"None", title:"NoStyleSheet"},\n caseDefault: { text:"Default", title:"StyleSheet" }\n\n },\n pagetemplate: {\n tag: ["PageTemplates","PageTemplate","pageTemplates","pageTemplate","pagetemplate","pagetemplates"],\n theDefault: "PageTemplate",\n suffix: "PageTemplate",\n notify: refreshPageTemplate,\n cookie: "txtPageTemplate",\n otherThing: "style",\n label: "Choose PageTemplate: ",\n tooltip: "Choose a PageTemplate",\n caseNone: { text:"None", title:"NoPageTemplate"},\n caseDefault: { text:"Default", title:"PageTemplate" }\n }\n\n },\n\n specialCases: ["caseNone","caseDefault"]\n\n};\n\nTiddlyWiki.prototype.removeNotification = function(title,fn) {\n for (var i=0;i<this.namedNotifications.length;i++)\n if((this.namedNotifications[i].name == title) && (this.namedNotifications[i].notify == fn))\n this.namedNotifications.splice(i,1); // counting on it only being there once\n}\n\n\nvar things = config.SelectTheme.things;\nvar specialCases=config.SelectTheme.specialCases;\n\nfor (var zz in things) {\n // make sure we have a value\n if (!config.options[things[zz].cookie])\n config.options[things[zz].cookie] = things[zz].theDefault;\n\n // remove core notify\n store.removeNotification(things[zz].theDefault,things[zz].notify);\n\n // and add our one\n store.addNotification(config.options[things[zz].cookie],things[zz].notify);\n\n}\n\n//checks to see if a tiddler exists in store or as a shadow.\nTiddlyWiki.prototype.isTiddler= function (title)\n {return store.tiddlerExists(title) || store.isShadowTiddler(title)}\n\n//hijack core function & make sure template exists\nwindow.applyPageTemplate_themeSelect=window.applyPageTemplate;\nwindow.applyPageTemplate=function(title){\n if(!store.isTiddler(title))\n {title = things.pagetemplate.theDefault;}\n applyPageTemplate_themeSelect(title);\n }\n\nTiddlyWiki.prototype.makeActiveTheme = function(what,title,alsoCheckOtherThing) {\n\n var thing = things[what];\n if (!store.isTiddler(title))\n title = thing.theDefault;\n\n var oldTitle = config.options[thing.cookie];\n\n if (what == "style") {\n // remove old style element from DOM\n var oldStyleElement = document.getElementById(oldTitle);\n oldStyleElement.parentNode.removeChild(oldStyleElement);\n }\n\n store.removeNotification(oldTitle,thing.notify);\n store.addNotification(title,thing.notify);\n store.notify(title);\n\n config.options[thing.cookie] = title;\n saveOptionCookie(thing.cookie);\n if (alsoCheckOtherThing)\n this.makeActiveTheme(thing.otherThing,\n title.replace(new RegExp(thing.suffix+"$"),"") + things[thing.otherThing].suffix,\n false);\n};\n\n\nconfig.shadowTiddlers.NoStyleSheet = "";\nconfig.shadowTiddlers.NoPageTemplate = config.shadowTiddlers.PageTemplate;\n\n\nfunction switchTheme(e){\n if (!e) var e = window.event;\n var theTarget = resolveTarget(e);\n var theLink = theTarget;\n var switchTo= theLink.getAttribute("switchTo");\n var mode = theLink.getAttribute("mode");\n if ((config.options[things[mode].cookie])!=switchTo)\n {store.makeActiveTheme(mode,switchTo,true);};\n return(false);\n}\n\n\nconfig.macros.themeSelect={};\nconfig.macros.themeSelect.dropdownchar = (document.all?"▼":"▾");\nconfig.macros.themeSelect.handler = function(place,macroName,params,wikifier,paramString,tiddler){\n var arrow = config.macros.themeSelect.dropdownchar;\n var mode = params[0];\n var label = (params[1]?params[1]:things[mode].label) + arrow;\n var cookie = (config.options[things[mode].cookie]);\n\n var onclick = function(e)\n { if (!e) var e = window.event;\n var popup = Popup.create(this);\n\n var tagged=[];\n\n store.forEachTiddler(function(title,tiddler) {\n if ((tiddler.tags).containsAny(things[mode].tag)){\n tagged.push(tiddler.title);}\n });\n\n //integrate ThemePacks\n if (config.themes) {\n // see what themes have been loaded...\n for (var i=0;i<config.themes.length;i++) {\n // see if there is one\n var lookForThis = config.themes[i] + things[mode].suffix;\n if (store.isShadowTiddler(lookForThis)) {\n tagged.pushUnique(lookForThis);\n }\n }\n tagged = tagged.sort();\n }\n\n //this function used later to create buttons\n var createThemeButton = function(switchTo){\n var theButton = createTiddlyButton(createTiddlyElement(popup,"li"),text,null,switchTheme,useClass);\n theButton.setAttribute("switchTo",switchTo);\n theButton.setAttribute("mode",mode);};\n\n //create Buttons for None(shadow styles) & Default (StyleSheet)\n // Default button is not created if StyleSheet doesnt exist.\n for(var t=0; t<specialCases.length; t++){\n var special = specialCases[t];\n var text = things[mode][special].text;\n var useClass = "tiddlyLinkExisting"; //redundant, optimize!\n if ((things[mode][special].title==cookie)||(special=="caseNone"&&!store.isTiddler(cookie)))\n {text+= " [x]";\n useClass = "currentlySelected";}\n if (!((special=="caseDefault")&&(!store.getTiddler(things[mode][special].title))))\n createThemeButton(things[mode][special].title); }\n\n //insert horizontal rule\n createTiddlyElement(createTiddlyElement(popup,"li"),"hr");\n\n //create buttons for all other stylesheet tiddlers\n for(var t=0; t<tagged.length; t++)\n { var useClass = "tiddlyLinkExisting";\n var text = (tagged[t]).replace((things[mode].suffix),"");\n if (tagged[t]==(cookie) )\n {text+=" [x]"; useClass="currentlySelected";}\n if ((tagged[t]!= (things[mode].theDefault))&&tagged[t]!= (things[mode].none))\n {createThemeButton(tagged[t]);}}\n Popup.show(popup,false);\n e.cancelBubble = true;\n if (e.stopPropagation)\n e.stopPropagation();\n return(false);\n };\n\n var createdropperButton = function(place){\n var sp = createTiddlyElement(place,"span",null,"ThemeChooserButton");\n var theDropDownBtn = createTiddlyButton(sp,label,things[mode].tooltip,onclick);\n };\n\n createdropperButton(place);\n};\n\n\nsetStylesheet(".popup li a.currentlySelected {background:#ccc;color:black;font-weight:bold;}","currentlySelectedStyle"); // could do better probably...\n\nconfig.macros.layoutChooser=config.macros.themeSelect;\n\n//shadow tiddler to hold instructions for creating ThemePacks\nconfig.shadowTiddlers.ThemePack='See http://simonbaird.com/mptw/#CreateThemePack'; \n\nconfig.macros.applyTheme = {handler: function (place,macroName,params,wikifier,paramString,tiddler) {\n var theme = params[0];\n var label = params[1]?params[1]:'Apply theme "' + theme + '"';\n var tooltip = 'Apply the "'+theme+'" theme to this TiddlyWiki';\n createTiddlyButton(place,label,tooltip,function() {\n store.makeActiveTheme("style",theme+things.style.suffix,true);\n });\n}};\n\n\n// this means you can put #theme:ThemeName in url. suggested by Clint\nconfig.paramifiers.theme = {\n onstart: function(themeName) {\n store.makeActiveTheme("style",themeName+config.SelectTheme.things.style.suffix,true);\n }\n};\n\n//}}}\n
>If you haven't yet looked at [[Inheriting the Tiddler Styles]], do so now, as this builds on the techniques described there.\nNow that we've solved the problems of making the iframe appear within a tiddler seamlessly, there's one more issue we need to deal with. How high should the iframe be? Often, what you want is for the iframe to be just big enough to display its content and no more. Yes, you could play with {{{<iframe height="xx">}}} but what if the font sizes in the ~TiddlyWiki are changed and thus those changes are inherited by the iframe content? Or what if you want to re-style the iframe's content? Or what if the iframe is displaying dynamic data from some web server (see [[Refreshing the <iframe>]])? The data could change in length, style, whatever. \n\nBottom line: we really need a self-sizing iframe! Fortunately, with all we have already done to inherit the host ~TiddlyWiki's CSS and force the iframe's body backbround to the tiddler's background, only a tiny bit more Javascript is needed in the iframe content! Remember this at the bottom of the [[Template <iframe> Source]]?\n{{{\n<script language="Javascript" type="text/javascript">\n document.body.style.backgroundColor = \n getStyle(document.getElementById("tdiv"), 'background-color');\n</script>\n}}}\nTo make the iframe self-sizing, there are a couple of things we need to do:\n#Add an {{{id=}}} attribute to the {{{<iframe>}}} tag in the tiddler. My convention is to use the file-name portion of the iframe's {{{src}}} as the {{{id}}}. See the second example in [[Embedding the <iframe>]]. Note that I also set {{{<iframe height="0"...>}}} This is a fine point: when the tiddler is opened, the animation runs for the tiddler with a 0-height embedded iframe, then when it completes rendering the tiddler grows vertically to the size it needs to hold the auto-sized iframe.\n#Add a bit more code to the Javascript at the bottom of the iframe's source so that it sets the host tiddler's {{{<iframe>}}} tag {{{height}}} equal to the {{{offsetHeight}}} of the class=tiddler div in the iframe.\nBefore:\n{{{\n<script language="Javascript" type="text/javascript">\n document.body.style.backgroundColor = \n getStyle(document.getElementById("tdiv"), 'background-color');\n</script>\n}}}\nAfter (with refactoring):\n{{{\n<script language="Javascript" type="text/javascript">\n var tdiv = document.getElementById('tdiv');\n document.body.style.backgroundColor = getStyle(tdiv, 'background-color');\n parent.document.getElementById("arunscript").height = tdiv.offsetHeight + 16;\n</script>\n}}}\nWe use the offsetHeight of the class=tiddler div, not the body, because that's the height of the live content! I added 16 pixels of "slop" to the hright because I found that sometimes a scroller would appear needlessly (if scrolling of the iframe is set to "on" or "auto"). You can play with this.\n\n\n
<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY'>><<saveChanges>><<themeSelect style 'select theme'>><<slider chkSliderOptionsPanel OptionsPanel 'options »' 'Change TiddlyWiki advanced options'>>
\nHow to seamlessly integrate [[<iframe>]] elements in [[TiddlyWiki|http://www.tiddlywiki.com/]]
Magic With [[<iframe>]]
/***\nPlace your custom CSS here\n***/\n/*{{{*/\ntextarea {\n font-family:Lucida Console, Courier New, Courier, monospace !important;\n}\n/*}}}*/\n
{{{\n<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" \n "http://www.w3.org/TR/REC-html40/loose.dtd">\n<html>\n<head>\n<script src="iframecss.js"></script>\n<!-- parent's stylesheets get inserted here -->\n<style>\n .tiddler { border: none; margin: 0; padding: 0; }\n .viewer { border: none; margin: 0; padding: 0; }\n</style>\n</head>\n<body>\n<div class="tiddler" id="tdiv"><div class="viewer" id="vdiv">\n}}}\n{{{the content of the iframe goes here. Anything goes!}}}\n{{{\n</div></div>\n<script language="Javascript" type="text/javascript">\n document.body.style.backgroundColor = \n getStyle(document.getElementById("tdiv"), 'background-color');\n</script>\n</body>\n</html>\n}}}
{{{\n//\n// Client-side JS common to <iframe> usage within TiddlyWiki.\n//\n// These functions, and the startup code that follows, drag all of\n// the parent TiddlyWiki's styles into the document that includes\n// this code. It's designed to be included in an iframe that will be\n// embedded into a tiddler. This gives the iframe access to all of\n// the CSS that TiddlyWiki has! Every time the iframe is reloaded\n// the parent TW's styles get again dragged in. This allows the\n// iframe to follow TW theme/style changes!\n//\n// Typically, this would be followed (in the iframe HTML) by something\n// like\n//\n// <style>\n// .tiddler { border: none; margin: 0; padding: 0;}\n// .viewer { border: none; margin: 0; padding: 0;}\n// </style>\n//\n// to get rid of any border, margins, and padding that may be in\n// effect, leaving the iframe with the color, fonts, background, etc. \n// of the tiddler. Within the iframe HTML, enclose everything in\n//\n// <div class="tiddler" id="tdiv"><div class="viewer">...</div></div>\n//\n// This will cause the contents of the iframe to match the parent \n// tiddler! One more thing needs to be done at the END of the\n// iframe code:\n//\n// <script language="Javascript" type="text/javascript" runat="client">\n// var tdiv = document.getElementById("tdiv");\n// document.body.style.backgroundColor = \n// getStyle(document.getElementById("tdiv"), 'background-color');\n// </script>\n//\n// This makes the body of the iframe's background match that of the \n// tiddler div, so that if the iframe's content doesn't fill the frame,\n// the rest of it will match the tiddler's b/g color.\n//\n// 27-Sep-2006 rbd Initial edit, with code lifted from elsewhere.\n//\n\n//\n// Get the computed css property - sweet!\n// http://www.robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/\n//\nfunction getStyle(oElm, strCssRule) \n{\n var strValue = "";\n if(document.defaultView && document.defaultView.getComputedStyle){ // FF & friends\n strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);\n }\n else if(oElm.currentStyle){ // IE\n // Convert to camelCase form for IE (e.g., background-color -> backgroundColor)\n strCssRule = strCssRule.replace(/\s-(\sw)/g, function (strMatch, p1){\n return p1.toUpperCase();\n });\n strValue = oElm.currentStyle[strCssRule];\n }\n return strValue;\n}\n//\n// Stolen from TiddlyWiki: Add a stylesheet, given the style text.\n//\nfunction setStylesheet(s, id)\n{\n var n = document.getElementById(id);\n if(document.createStyleSheet) // Test for IE's non-standard createStyleSheet method\n {\n if(n)\n n.parentNode.removeChild(n);\n // This failed without the &nbsp;\n document.getElementsByTagName("head")[0].insertAdjacentHTML("beforeEnd",\n "&nbsp;<style id='" + id + "'>" + s + "</style>");\n }\n else\n {\n if(n)\n n.replaceChild(document.createTextNode(s),n.firstChild);\n else\n {\n n = document.createElement("style");\n n.type = "text/css";\n n.id = id;\n n.appendChild(document.createTextNode(s));\n document.getElementsByTagName("head")[0].appendChild(n);\n }\n }\n}\n//\n// Create duplicates of iframe parent's stylesheets here\n//\nvar sheets = parent.document.getElementsByTagName("style");\nfor(i = 0; i < sheets.length; i++) {\n setStylesheet(sheets[i].innerHTML, "pcss_" + i);\n}\n}}}